Skip to content

feat(shadcn): add className prop support to all components#216

Open
nil957 wants to merge 1 commit intovercel-labs:mainfrom
nil957:feat/shadcn-className-support
Open

feat(shadcn): add className prop support to all components#216
nil957 wants to merge 1 commit intovercel-labs:mainfrom
nil957:feat/shadcn-className-support

Conversation

@nil957
Copy link

@nil957 nil957 commented Mar 13, 2026

Summary

Addresses #145

Adds optional className prop to all shadcn components for custom styling, matching how shadcn/ui itself works.

Changes

Catalog (packages/shadcn/src/catalog.ts)

  • Added className: z.string().nullable() to all 36+ component schemas

Components (packages/shadcn/src/components.tsx)

  • Forward className to root elements via cn(existingClasses, props.className)

Example

Before

{
  "type": "Card",
  "props": { "title": "Stats" }
}

→ Forced to use gap-3 on CardContent, no override possible

After

{
  "type": "Card",
  "props": {
    "title": "Stats",
    "className": "gap-1"
  }
}

→ Can override to gap-1 for compact stat cards

Use Cases

  • Override default spacing (gap, padding, margin)
  • Add responsive utilities (hidden md:block)
  • Fine-tune without creating custom components
  • Match rest of shadcn/ui ecosystem conventions

Checklist

Addresses vercel-labs#145

Adds optional `className` prop to all 36+ shadcn components for custom
styling. The prop is forwarded to the root element via cn(), matching
how shadcn/ui itself works.

Changes:
- Added `className: z.string().nullable()` to all component schemas
- Forward className to root element: cn(existingClasses, props.className)
- Enables fine-tuning without rewriting entire components

Example:
```json
{
  "type": "Card",
  "props": {
    "title": "Stats",
    "className": "gap-1"
  }
}
```

This overrides the default gap-3 on CardContent.
@vercel
Copy link
Contributor

vercel bot commented Mar 13, 2026

Someone is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

</CardHeader>
)}
<CardContent className="flex flex-col gap-3">{children}</CardContent>
<CardContent className={cn("flex flex-col gap-3", props.className)}>{children}</CardContent>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

props.className is applied to internal child elements of components in addition to (or instead of) the root element, causing user-provided classes to break internal component styling.

Fix on Vercel

label: z.string(),
value: z.string(),
}),

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The className prop was incorrectly placed inside z.array(z.object({...})) item schemas instead of at the component-level props, corrupting the schema for 6 components (Tabs, Accordion, Carousel, DropdownMenu, ToggleGroup, ButtonGroup).

Fix on Vercel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant